﻿#include "ssContext.h"
#include <malloc.h>
#include <stdio.h>


namespace StarSeeker
{

ssContext::ssContext()
#ifdef SS_USE_WINDOWS
	:m_main(0), m_context(0), m_state(CS_NULL), m_stackSize(10240)
#else
	:m_main(0), m_state(CS_NULL), m_stack(0), m_stackSize(10240)
#endif
{
}

ssContext::~ssContext()
{
#ifdef SS_USE_WINDOWS
	if(m_context)
		DeleteFiber(m_context);
#else
	if (m_stack)
		::free(m_stack);
#endif
}

void ssContext::Create(void* mainContext, unsigned int stackSize)
{
	if (stackSize==0) return;
	m_stackSize = stackSize;
#ifdef SS_USE_WINDOWS
	m_main = mainContext;
	if (m_context) return;
	m_context = CreateFiber(m_stackSize, ssContext::ContextFunc, this);
#else
	m_main = (ucontext_t*)mainContext;
	if (m_stack) return;
	if (0==getcontext(&m_context))
	{
		m_stack = ::malloc(stackSize);
		m_context.uc_stack.ss_sp = m_stack;
		m_context.uc_stack.ss_size = m_stackSize;
		m_context.uc_stack.ss_flags = 0;
		m_context.uc_link = m_main;
		makecontext(&m_context, (void(*)(void))ssContext::ContextFunc, 1, this);
	}
#endif
	m_state = CS_READY;
}

void ssContext::Run()
{
	if (m_state != CS_READY && m_state != CS_SUSPEND)
		return;

	m_state = CS_RUNING;
#ifdef SS_USE_WINDOWS
	SwitchToFiber(m_context);
#else
	swapcontext(m_main, &m_context);
#endif
}

void ssContext::YieldReturn()
{
	m_state = CS_SUSPEND;
#ifdef SS_USE_WINDOWS
	SwitchToFiber(m_main);
#else
	swapcontext(&m_context, m_main);
#endif
}

StarSeeker::CONTEXT_STATE ssContext::State()
{
	return m_state;
}

void ssContext::Stop()
{
	m_state = CS_END;
}

#ifdef SS_USE_WINDOWS
VOID WINAPI ssContext::ContextFunc(PVOID param)
{
	ssContext* p = reinterpret_cast<ssContext*>(param);
	p->ContextMemberFunc();
	p->m_state = CS_END;
	SwitchToFiber(p->m_main);
}
#else
void ssContext::ContextFunc(void* param)
{
	ssContext* p = reinterpret_cast<ssContext*>(param);
	p->ContextMemberFunc();
	p->m_state = CS_END;
}
#endif

void ssContext::ContextMemberFunc()
{
	printf("%u MemFunc1\n", this);
	YieldReturn();
	printf("%u MemFunc2\n", this);
	YieldReturn();
	printf("%u MemFunc3\n", this);
}

}
